library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.4     ✓ purrr   0.3.4
✓ tibble  3.1.2     ✓ dplyr   1.0.7
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(MatrixGenerics)
Loading required package: matrixStats

Attaching package: ‘matrixStats’

The following object is masked from ‘package:dplyr’:

    count


Attaching package: ‘MatrixGenerics’

The following objects are masked from ‘package:matrixStats’:

    colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, colCounts, colCummaxs, colCummins, colCumprods, colCumsums, colDiffs, colIQRDiffs, colIQRs,
    colLogSumExps, colMadDiffs, colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats, colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
    colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads, colWeightedMeans, colWeightedMedians, colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs, rowAnys,
    rowAvgsPerColSet, rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods, rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, rowMadDiffs, rowMads,
    rowMaxs, rowMeans2, rowMedians, rowMins, rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs,
    rowVars, rowWeightedMads, rowWeightedMeans, rowWeightedMedians, rowWeightedSds, rowWeightedVars
library(SingleCellExperiment)
Loading required package: SummarizedExperiment
Loading required package: GenomicRanges
Loading required package: stats4
Loading required package: BiocGenerics
Loading required package: parallel

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:parallel’:

    clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap, parApply, parCapply, parLapply, parLapplyLB, parRapply, parSapply, parSapplyLB

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep, grepl, intersect,
    is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
    table, tapply, union, unique, unsplit, which.max, which.min

Loading required package: S4Vectors

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:dplyr’:

    first, rename

The following object is masked from ‘package:tidyr’:

    expand

The following objects are masked from ‘package:base’:

    expand.grid, I, unname

Loading required package: IRanges

Attaching package: ‘IRanges’

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

The following object is masked from ‘package:purrr’:

    reduce

Loading required package: GenomeInfoDb
Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see 'citation("Biobase")', and for packages 'citation("pkgname")'.


Attaching package: ‘Biobase’

The following object is masked from ‘package:MatrixGenerics’:

    rowMedians

The following objects are masked from ‘package:matrixStats’:

    anyMissing, rowMedians
lseq <- function(from, to, length.out){
  exp(seq(log(from), log(to), length.out = length.out))
}
theme_set(cowplot::theme_cowplot())
library(org.Hs.eg.db)
Loading required package: AnnotationDbi

Attaching package: ‘AnnotationDbi’

The following object is masked from ‘package:dplyr’:

    select
human_cell_cycle_genes <- select(org.Hs.eg.db, keytype = "GOALL", keys = "GO:0007049", columns = "ENSEMBL")[, "ENSEMBL"]
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
'select()' returned 1:many mapping between keys and columns
library(org.Mm.eg.db)
mouse_cell_cycle_genes <- select(org.Mm.eg.db, keytype = "GOALL", keys = "GO:0007049", columns = "ENSEMBL")[, "ENSEMBL"]
'select()' returned 1:many mapping between keys and columns
mu_sup <- lseq(1e-4, 1e6, length.out = 1001)
poisson_pred <- cross_df(list(mu = mu_sup, factor = 10^seq(-8, 8))) %>%
  mutate(var = mu * factor)

gampoi_pred <- cross_df(list(mu = mu_sup, factor = 10^seq(-2, 2, by = 2))) %>%
  mutate(var = mu + mu^2 * factor) 

Prepare Data

Download data

# Work around for some bug in zellkonverter
# https://github.com/theislab/zellkonverter/issues/45
setAs("dgRMatrix", to = "dgCMatrix", function(from){
  as(as(from, "CsparseMatrix"), "dgCMatrix")
})
if(! file.exists("../data/klein_2015.h5ad")){
  download.file("https://data.caltech.edu/tindfiles/serve/f0d567c5-cea6-4a60-923e-e9fb4a4019e8/", "../data/klein_2015.h5ad")
}
if(! file.exists("../data/svensson_2017_1.h5ad")){
  download.file("https://data.caltech.edu/tindfiles/serve/3f89d3a5-6ceb-486e-95d4-9bd3f511a706/", "../data/svensson_2017_1.h5ad")
}
if(! file.exists("../data/svensson_2017_2.h5ad")){
  download.file("https://data.caltech.edu/tindfiles/serve/16dab9ea-4447-4e23-9aad-e68d052fd789/", "../data/svensson_2017_2.h5ad")
}
if(! file.exists("../data/nih3t3.h5ad")){
  download.file("https://data.caltech.edu/tindfiles/serve/a448e98e-89cd-47b3-a134-803bbde29781/", "../data/nih3t3.h5ad")
}
if(! file.exists("../data/hek293t.h5ad")){
  download.file("https://data.caltech.edu/tindfiles/serve/b2758046-9247-43ab-b8f0-68882b4f39a3/", "../data/hek293t.h5ad")
}
if(! file.exists("../data/nci-h1975.Rds")){
  download.file("https://github.com/LuyiTian/sc_mixology/raw/master/data/csv/sc_10x.metadata.csv.gz", "../data/nci-h1975-metadata.csv.gz") 
  meta <- read.csv("../data/nci-h1975-metadata.csv.gz")
  meta$cell_id <- rownames(meta)
  
  download.file("https://github.com/LuyiTian/sc_mixology/raw/master/data/csv/sc_10x.count.csv.gz", "../data/nci-h1975.csv.gz") 
  count_mat <- as.matrix(read.csv("../data/nci-h1975.csv.gz"))
  gene_info <- AnnotationHub::AnnotationHub()[["AH53537"]] %>%
    as.data.frame() %>%
    group_by(gene_id) %>%
    summarize(chromosome = dplyr::first(seqnames),
              gene_name = dplyr::first(gene_name),
              gene_biotype = dplyr::first(gene_biotype))
  row_df <- tibble(gene_id = rownames(count_mat)) %>%
    left_join((gene_info), by = "gene_id") %>%
    as.data.frame()
  saveRDS(SummarizedExperiment(S4Vectors::SimpleList(counts = count_mat), colData = meta, rowData = row_df), "../data/nci-h1975.Rds")
}
if(! file.exists( "../data/GSE126321.Rds")){
  download.file("https://www.ncbi.nlm.nih.gov/geo/download/?acc=GSE126321&format=file", "../data/GSE126321_RAW.tar")
  dir.create("../data/GSE126321")
  untar("../data/GSE126321_RAW.tar", exdir = "../data/GSE126321")
  mat <- Matrix::readMM("../data/GSE126321/GSM3596320_GM18502_matrix.mtx.gz")
  genes <- read_tsv("../data/GSE126321/GSM3596320_GM18502_genes.tsv.gz", col_names = c("gene_id", "gene_name"))
  barcodes <- read_tsv("../data/GSE126321/GSM3596320_GM18502_barcodes.tsv.gz", col_names = "barcode") %>%
    mutate(barcode = str_remove(barcode, "-1"))
  qc <- read.delim("../data/GSE126321/GSM3596320_GM18502_cellQC.tsv.gz", sep = "\t") %>%
    rownames_to_column("barcode")  %>%
    as_tibble()
  col_df <- left_join(barcodes, qc, by = "barcode") %>%
    as.data.frame()
  gene_info <- AnnotationHub::AnnotationHub()[["AH53537"]] %>%
    as.data.frame() %>%
    group_by(gene_id) %>%
    summarize(chromosome = dplyr::first(seqnames),
              gene_name = dplyr::first(gene_name),
              gene_biotype = dplyr::first(gene_biotype))
  row_df <- genes %>%
    left_join((gene_info), by = "gene_id") %>%
    transmute(gene_id, gene_name = gene_name.x, chromosome, gene_biotype) %>%
    as.data.frame()
  count_mat <- as(mat, "dgCMatrix")
  rownames(count_mat) <- row_df$gene_id
  colnames(count_mat) <- col_df$barcode
  saveRDS(SummarizedExperiment(S4Vectors::SimpleList(counts = count_mat), colData = col_df, rowData = row_df), "../data/GSE126321.Rds")
}

Technical control experiments

se <- zellkonverter::readH5AD("../data/klein_2015.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 25213   424
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    geom_line(data = gampoi_pred %>% filter((factor == 100 & var < 1.5e3) | (factor != 100 & var < 4e3)), 
              aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
    annotate(shadowtext:::GeomShadowText, x = 5e3, y = 5e3, label = expression(Var==mu),
             hjust = 0, vjust = 0.5, angle = 45, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(4e3), y = 4e3, label = expression(Var==mu+1*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(5e3 / 0.01), y = 5e3, label = expression(Var==mu+0.01*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(2e3 / 100), y = 2e3, label = expression(Var==mu+100*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
    ggtitle("Klein 2015", subtitle = "<span style = 'color: #6c58d1'>ERCC spike-ins</span>") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'

tech_p1 <- last_plot()
se <- zellkonverter::readH5AD("../data/svensson_2017_1.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 17906   894
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    # geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
    ggtitle("Svensson 2017 (1)", subtitle = "") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

tech_p2 <- last_plot()
se <- zellkonverter::readH5AD("../data/svensson_2017_2.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 18812   803
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    # geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
    ggtitle("Svensson 2017 (2)", subtitle = "") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

tech_p3 <- last_plot()

Biological control

se <- zellkonverter::readH5AD("../data/nih3t3.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 19406   788
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% paste0("mm10_", mouse_cell_cycle_genes)) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    geom_line(data = gampoi_pred %>% filter((factor == 100 & var < 1.5e3) | (factor != 100 & var < 4e3)), 
              aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    # geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    # geom_point(size = 0.3, alpha = 0.3) +
    ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
    annotate(shadowtext:::GeomShadowText, x = 5e3, y = 5e3, label = expression(Var==mu),
             hjust = 0, vjust = 0.5, angle = 45, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(4e3), y = 4e3, label = expression(Var==mu+1*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(5e3 / 0.01), y = 5e3, label = expression(Var==mu+0.01*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotate(shadowtext:::GeomShadowText, x = sqrt(2e3 / 100), y = 2e3, label = expression(Var==mu+100*mu^2),
             hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
    ggtitle("NIH/3T3 Cells", subtitle = "<span style = 'color: #87172f'>Cell cycle marker</span> genes.") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'

p1 <- last_plot()
se <- zellkonverter::readH5AD("../data/hek293t.h5ad")

sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 22804   565
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% paste0("hg19_", human_cell_cycle_genes)) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    # geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
    ggtitle("HEK 293T Cells", subtitle = "") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

p2 <- last_plot()
se_full <- readRDS("../data/nci-h1975.Rds")
table(se_full$cell_line)

 H1975  H2228 HCC827 
   313    315    274 
se <- se_full[, se_full$cell_line == "H1975"]

sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 15932    99
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% human_cell_cycle_genes) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    # geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
    ggtitle("NCI-H1975 Cells", subtitle = "") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

p3 <- last_plot()
se <- readRDS("../data/GSE126321.Rds")
# table(se$cellPhase)
# se <- se[, se$cellPhase == "S"]

sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)


se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 17909  1242
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% human_cell_cycle_genes) %>%
  mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
  ggplot(aes(x = mu, y = var)) +
    geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
    # geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
    # geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
    geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
    geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
    coord_fixed(expand = FALSE, clip = "off") +
    ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
    annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
                        short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
    scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Mean~(mu))) +
    scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
                  labels = c(expression(10^-3), expression(10^-1), 
                             expression(10),  expression(10^3), expression(10^5)),
                  name = expression(Variance)) +
    scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
    ggtitle("GM18502 Cells", subtitle = "") +
    theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 1812 rows containing missing values (geom_point).

p4 <- last_plot()
p_tech <- cowplot::plot_grid(tech_p1, tech_p2, tech_p3, NULL, nrow = 1, align = "h")
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
p_bio <- cowplot::plot_grid(p1, p2, p3, p4, nrow = 1, align = "h")
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'expression'
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 1812 rows containing missing values (geom_point).
tech_title <- cowplot::ggdraw() + cowplot::draw_label("(A) Droplets with RNA solution (technical control)", 
                                                      fontface = "bold", x = 0.02, hjust = 0, size = 18)
bio_title <- cowplot::ggdraw() + cowplot::draw_label("(B) Cell line populations (biological control)", 
                                                     fontface = "bold", x = 0.02, hjust = 0, size = 18)

p_res <- cowplot::plot_grid(tech_title, p_tech, bio_title, p_bio, ncol = 1,
                            rel_heights = c(0.2, 1, 0.2, 1))
p_res

cowplot::save_plot("../output/mean_variance_relation_homnogeneous_cells.pdf", p_res, nrow = 2, ncol = 4, base_asp = 0.68, base_height = 5)

Session Info

sessionInfo()
R version 4.1.0 (2021-05-18)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.6

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] org.Mm.eg.db_3.13.0         org.Hs.eg.db_3.13.0         AnnotationDbi_1.54.1        SingleCellExperiment_1.14.1 SummarizedExperiment_1.22.0 Biobase_2.52.0             
 [7] GenomicRanges_1.44.0        GenomeInfoDb_1.28.0         IRanges_2.26.0              S4Vectors_0.30.0            BiocGenerics_0.38.0         MatrixGenerics_1.4.0       
[13] matrixStats_0.59.0          forcats_0.5.1               stringr_1.4.0               dplyr_1.0.7                 purrr_0.3.4                 readr_1.4.0                
[19] tidyr_1.1.3                 tibble_3.1.2                ggplot2_3.3.4               tidyverse_1.3.1            

loaded via a namespace (and not attached):
  [1] ggbeeswarm_0.6.0              colorspace_2.0-1              ellipsis_0.3.2                markdown_1.1                  XVector_0.32.0                fs_1.5.0                     
  [7] gridtext_0.1.4                ggtext_0.1.1                  rstudioapi_0.13               farver_2.1.0                  bit64_4.0.5                   interactiveDisplayBase_1.30.0
 [13] fansi_0.5.0                   lubridate_1.7.10              xml2_1.3.2                    sparseMatrixStats_1.4.0       cachem_1.0.5                  knitr_1.33                   
 [19] jsonlite_1.7.2                Cairo_1.5-12.2                broom_0.7.7                   dbplyr_2.1.1                  png_0.1-7                     shiny_1.6.0                  
 [25] BiocManager_1.30.16           compiler_4.1.0                httr_1.4.2                    basilisk_1.4.0                backports_1.2.1               assertthat_0.2.1             
 [31] Matrix_1.3-4                  fastmap_1.1.0                 cli_2.5.0                     later_1.2.0                   htmltools_0.5.1.1             tools_4.1.0                  
 [37] gtable_0.3.0                  glue_1.4.2                    GenomeInfoDbData_1.2.6        rappdirs_0.3.3                Rcpp_1.0.6                    cellranger_1.1.0             
 [43] vctrs_0.3.8                   Biostrings_2.60.1             zellkonverter_1.2.0           xfun_0.24                     rvest_1.0.0                   mime_0.10                    
 [49] lifecycle_1.0.0               AnnotationHub_3.0.0           zlibbioc_1.38.0               scales_1.1.1                  basilisk.utils_1.4.0          ragg_1.1.3                   
 [55] hms_1.1.0                     promises_1.2.0.1              yaml_2.2.1                    curl_4.3.1                    memoise_2.0.0                 reticulate_1.20              
 [61] ggrastr_0.2.3                 stringi_1.6.2                 RSQLite_2.2.7                 BiocVersion_3.13.1            filelock_1.0.2                systemfonts_1.0.2            
 [67] rlang_0.4.11                  pkgconfig_2.0.3               bitops_1.0-7                  lattice_0.20-44               shadowtext_0.0.8              cowplot_1.1.1                
 [73] bit_4.0.4                     tidyselect_1.1.1              magrittr_2.0.1                R6_2.5.0                      generics_0.1.0                DelayedArray_0.18.0          
 [79] DBI_1.1.1                     pillar_1.6.1                  haven_2.4.1                   withr_2.4.2                   KEGGREST_1.32.0               RCurl_1.98-1.3               
 [85] dir.expiry_1.0.0              modelr_0.1.8                  crayon_1.4.1                  utf8_1.2.1                    BiocFileCache_2.0.0           grid_4.1.0                   
 [91] readxl_1.3.1                  blob_1.2.1                    reprex_2.0.0                  digest_0.6.27                 xtable_1.8-4                  httpuv_1.6.1                 
 [97] textshaping_0.3.5             munsell_0.5.0                 beeswarm_0.4.0                vipor_0.4.5                  
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShNYXRyaXhHZW5lcmljcykKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKYGBgCgpgYGB7cn0KbHNlcSA8LSBmdW5jdGlvbihmcm9tLCB0bywgbGVuZ3RoLm91dCl7CiAgZXhwKHNlcShsb2coZnJvbSksIGxvZyh0byksIGxlbmd0aC5vdXQgPSBsZW5ndGgub3V0KSkKfQp0aGVtZV9zZXQoY293cGxvdDo6dGhlbWVfY293cGxvdCgpKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkob3JnLkhzLmVnLmRiKQpodW1hbl9jZWxsX2N5Y2xlX2dlbmVzIDwtIHNlbGVjdChvcmcuSHMuZWcuZGIsIGtleXR5cGUgPSAiR09BTEwiLCBrZXlzID0gIkdPOjAwMDcwNDkiLCBjb2x1bW5zID0gIkVOU0VNQkwiKVssICJFTlNFTUJMIl0KbGlicmFyeShvcmcuTW0uZWcuZGIpCm1vdXNlX2NlbGxfY3ljbGVfZ2VuZXMgPC0gc2VsZWN0KG9yZy5NbS5lZy5kYiwga2V5dHlwZSA9ICJHT0FMTCIsIGtleXMgPSAiR086MDAwNzA0OSIsIGNvbHVtbnMgPSAiRU5TRU1CTCIpWywgIkVOU0VNQkwiXQpgYGAKCgpgYGB7cn0KbXVfc3VwIDwtIGxzZXEoMWUtNCwgMWU2LCBsZW5ndGgub3V0ID0gMTAwMSkKcG9pc3Nvbl9wcmVkIDwtIGNyb3NzX2RmKGxpc3QobXUgPSBtdV9zdXAsIGZhY3RvciA9IDEwXnNlcSgtOCwgOCkpKSAlPiUKICBtdXRhdGUodmFyID0gbXUgKiBmYWN0b3IpCgpnYW1wb2lfcHJlZCA8LSBjcm9zc19kZihsaXN0KG11ID0gbXVfc3VwLCBmYWN0b3IgPSAxMF5zZXEoLTIsIDIsIGJ5ID0gMikpKSAlPiUKICBtdXRhdGUodmFyID0gbXUgKyBtdV4yICogZmFjdG9yKSAKYGBgCgojIFByZXBhcmUgRGF0YQoKCiMjIERvd25sb2FkIGRhdGEKCmBgYHtyfQojIFdvcmsgYXJvdW5kIGZvciBzb21lIGJ1ZyBpbiB6ZWxsa29udmVydGVyCiMgaHR0cHM6Ly9naXRodWIuY29tL3RoZWlzbGFiL3plbGxrb252ZXJ0ZXIvaXNzdWVzLzQ1CnNldEFzKCJkZ1JNYXRyaXgiLCB0byA9ICJkZ0NNYXRyaXgiLCBmdW5jdGlvbihmcm9tKXsKICBhcyhhcyhmcm9tLCAiQ3NwYXJzZU1hdHJpeCIpLCAiZGdDTWF0cml4IikKfSkKYGBgCgoKYGBge3J9CmlmKCEgZmlsZS5leGlzdHMoIi4uL2RhdGEva2xlaW5fMjAxNS5oNWFkIikpewogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vZGF0YS5jYWx0ZWNoLmVkdS90aW5kZmlsZXMvc2VydmUvZjBkNTY3YzUtY2VhNi00YTYwLTkyM2UtZTlmYjRhNDAxOWU4LyIsICIuLi9kYXRhL2tsZWluXzIwMTUuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlLzNmODlkM2E1LTZjZWItNDg2ZS05NWQ0LTliZDNmNTExYTcwNi8iLCAiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzIuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlLzE2ZGFiOWVhLTQ0NDctNGUyMy05YWFkLWU2OGQwNTJmZDc4OS8iLCAiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzIuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9uaWgzdDMuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlL2E0NDhlOThlLTg5Y2QtNDdiMy1hMTM0LTgwM2JiZGUyOTc4MS8iLCAiLi4vZGF0YS9uaWgzdDMuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9oZWsyOTN0Lmg1YWQiKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9kYXRhLmNhbHRlY2guZWR1L3RpbmRmaWxlcy9zZXJ2ZS9iMjc1ODA0Ni05MjQ3LTQzYWItYjhmMC02ODg4MmI0ZjM5YTMvIiwgIi4uL2RhdGEvaGVrMjkzdC5oNWFkIikKfQppZighIGZpbGUuZXhpc3RzKCIuLi9kYXRhL25jaS1oMTk3NS5SZHMiKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL0x1eWlUaWFuL3NjX21peG9sb2d5L3Jhdy9tYXN0ZXIvZGF0YS9jc3Yvc2NfMTB4Lm1ldGFkYXRhLmNzdi5neiIsICIuLi9kYXRhL25jaS1oMTk3NS1tZXRhZGF0YS5jc3YuZ3oiKSAKICBtZXRhIDwtIHJlYWQuY3N2KCIuLi9kYXRhL25jaS1oMTk3NS1tZXRhZGF0YS5jc3YuZ3oiKQogIG1ldGEkY2VsbF9pZCA8LSByb3duYW1lcyhtZXRhKQogIAogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vZ2l0aHViLmNvbS9MdXlpVGlhbi9zY19taXhvbG9neS9yYXcvbWFzdGVyL2RhdGEvY3N2L3NjXzEweC5jb3VudC5jc3YuZ3oiLCAiLi4vZGF0YS9uY2ktaDE5NzUuY3N2Lmd6IikgCiAgY291bnRfbWF0IDwtIGFzLm1hdHJpeChyZWFkLmNzdigiLi4vZGF0YS9uY2ktaDE5NzUuY3N2Lmd6IikpCiAgZ2VuZV9pbmZvIDwtIEFubm90YXRpb25IdWI6OkFubm90YXRpb25IdWIoKVtbIkFINTM1MzciXV0gJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBncm91cF9ieShnZW5lX2lkKSAlPiUKICAgIHN1bW1hcml6ZShjaHJvbW9zb21lID0gZHBseXI6OmZpcnN0KHNlcW5hbWVzKSwKICAgICAgICAgICAgICBnZW5lX25hbWUgPSBkcGx5cjo6Zmlyc3QoZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICBnZW5lX2Jpb3R5cGUgPSBkcGx5cjo6Zmlyc3QoZ2VuZV9iaW90eXBlKSkKICByb3dfZGYgPC0gdGliYmxlKGdlbmVfaWQgPSByb3duYW1lcyhjb3VudF9tYXQpKSAlPiUKICAgIGxlZnRfam9pbigoZ2VuZV9pbmZvKSwgYnkgPSAiZ2VuZV9pZCIpICU+JQogICAgYXMuZGF0YS5mcmFtZSgpCiAgc2F2ZVJEUyhTdW1tYXJpemVkRXhwZXJpbWVudChTNFZlY3RvcnM6OlNpbXBsZUxpc3QoY291bnRzID0gY291bnRfbWF0KSwgY29sRGF0YSA9IG1ldGEsIHJvd0RhdGEgPSByb3dfZGYpLCAiLi4vZGF0YS9uY2ktaDE5NzUuUmRzIikKfQppZighIGZpbGUuZXhpc3RzKCAiLi4vZGF0YS9HU0UxMjYzMjEuUmRzIikpewogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VvL2Rvd25sb2FkLz9hY2M9R1NFMTI2MzIxJmZvcm1hdD1maWxlIiwgIi4uL2RhdGEvR1NFMTI2MzIxX1JBVy50YXIiKQogIGRpci5jcmVhdGUoIi4uL2RhdGEvR1NFMTI2MzIxIikKICB1bnRhcigiLi4vZGF0YS9HU0UxMjYzMjFfUkFXLnRhciIsIGV4ZGlyID0gIi4uL2RhdGEvR1NFMTI2MzIxIikKICBtYXQgPC0gTWF0cml4OjpyZWFkTU0oIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9tYXRyaXgubXR4Lmd6IikKICBnZW5lcyA8LSByZWFkX3RzdigiLi4vZGF0YS9HU0UxMjYzMjEvR1NNMzU5NjMyMF9HTTE4NTAyX2dlbmVzLnRzdi5neiIsIGNvbF9uYW1lcyA9IGMoImdlbmVfaWQiLCAiZ2VuZV9uYW1lIikpCiAgYmFyY29kZXMgPC0gcmVhZF90c3YoIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9iYXJjb2Rlcy50c3YuZ3oiLCBjb2xfbmFtZXMgPSAiYmFyY29kZSIpICU+JQogICAgbXV0YXRlKGJhcmNvZGUgPSBzdHJfcmVtb3ZlKGJhcmNvZGUsICItMSIpKQogIHFjIDwtIHJlYWQuZGVsaW0oIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9jZWxsUUMudHN2Lmd6Iiwgc2VwID0gIlx0IikgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oImJhcmNvZGUiKSAgJT4lCiAgICBhc190aWJibGUoKQogIGNvbF9kZiA8LSBsZWZ0X2pvaW4oYmFyY29kZXMsIHFjLCBieSA9ICJiYXJjb2RlIikgJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkKICBnZW5lX2luZm8gPC0gQW5ub3RhdGlvbkh1Yjo6QW5ub3RhdGlvbkh1YigpW1siQUg1MzUzNyJdXSAlPiUKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgIGdyb3VwX2J5KGdlbmVfaWQpICU+JQogICAgc3VtbWFyaXplKGNocm9tb3NvbWUgPSBkcGx5cjo6Zmlyc3Qoc2VxbmFtZXMpLAogICAgICAgICAgICAgIGdlbmVfbmFtZSA9IGRwbHlyOjpmaXJzdChnZW5lX25hbWUpLAogICAgICAgICAgICAgIGdlbmVfYmlvdHlwZSA9IGRwbHlyOjpmaXJzdChnZW5lX2Jpb3R5cGUpKQogIHJvd19kZiA8LSBnZW5lcyAlPiUKICAgIGxlZnRfam9pbigoZ2VuZV9pbmZvKSwgYnkgPSAiZ2VuZV9pZCIpICU+JQogICAgdHJhbnNtdXRlKGdlbmVfaWQsIGdlbmVfbmFtZSA9IGdlbmVfbmFtZS54LCBjaHJvbW9zb21lLCBnZW5lX2Jpb3R5cGUpICU+JQogICAgYXMuZGF0YS5mcmFtZSgpCiAgY291bnRfbWF0IDwtIGFzKG1hdCwgImRnQ01hdHJpeCIpCiAgcm93bmFtZXMoY291bnRfbWF0KSA8LSByb3dfZGYkZ2VuZV9pZAogIGNvbG5hbWVzKGNvdW50X21hdCkgPC0gY29sX2RmJGJhcmNvZGUKICBzYXZlUkRTKFN1bW1hcml6ZWRFeHBlcmltZW50KFM0VmVjdG9yczo6U2ltcGxlTGlzdChjb3VudHMgPSBjb3VudF9tYXQpLCBjb2xEYXRhID0gY29sX2RmLCByb3dEYXRhID0gcm93X2RmKSwgIi4uL2RhdGEvR1NFMTI2MzIxLlJkcyIpCn0KCmBgYAoKCiMgVGVjaG5pY2FsIGNvbnRyb2wgZXhwZXJpbWVudHMKCmBgYHtyfQpzZSA8LSB6ZWxsa29udmVydGVyOjpyZWFkSDVBRCgiLi4vZGF0YS9rbGVpbl8yMDE1Lmg1YWQiKQpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGVyY2NfZ2VuZSA9IHN0cl9zdGFydHMocm93bmFtZXMoc2VfcmVkKSwgIkVSQ0MtIikpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIoKGZhY3RvciA9PSAxMDAgJiB2YXIgPCAxLjVlMykgfCAoZmFjdG9yICE9IDEwMCAmIHZhciA8IDRlMykpLCAKICAgICAgICAgICAgICBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBlcmNjX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSA1ZTMsIHkgPSA1ZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGFuZ2xlID0gNDUsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRlKHNoYWRvd3RleHQ6OjpHZW9tU2hhZG93VGV4dCwgeCA9IHNxcnQoNGUzKSwgeSA9IDRlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMSptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDVlMyAvIDAuMDEpLCB5ID0gNWUzLCBsYWJlbCA9IGV4cHJlc3Npb24oVmFyPT1tdSswLjAxKm11XjIpLAogICAgICAgICAgICAgaGp1c3QgPSAwLCB2anVzdCA9IDAuNCwgYW5nbGUgPSBhdGFuKDIpIC8gcGkgKiAxODAsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRlKHNoYWRvd3RleHQ6OjpHZW9tU2hhZG93VGV4dCwgeCA9IHNxcnQoMmUzIC8gMTAwKSwgeSA9IDJlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMTAwKm11XjIpLAogICAgICAgICAgICAgaGp1c3QgPSAwLCB2anVzdCA9IDAuNCwgYW5nbGUgPSBhdGFuKDIpIC8gcGkgKiAxODAsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjNmM1OGQxIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJLbGVpbiAyMDE1Iiwgc3VidGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6ICM2YzU4ZDEnPkVSQ0Mgc3Bpa2UtaW5zPC9zcGFuPiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCgp0ZWNoX3AxIDwtIGxhc3RfcGxvdCgpCmBgYAoKCmBgYHtyfQpzZSA8LSB6ZWxsa29udmVydGVyOjpyZWFkSDVBRCgiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpCnNmIDwtIGNvbFN1bXMyKGFzc2F5KHNlKSkKdGhyZXMgPC0gcXVhbnRpbGUoc2YsIDAuNSkgKiBjKDEsIDEuMykKaGlzdChzZiwgYnJlYWtzID0gNTApOyBhYmxpbmUodiA9IHRocmVzLCBjb2wgPSAicmVkIiwgbHdkID0gMikKCnNlX3JlZCA8LSBzZVssIHNmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZl9yZWQgPC0gc2Zbc2YgPiB0aHJlc1sxXSAmIHNmIDwgdGhyZXNbMl1dCnNlX3JlZCA8LSBzZV9yZWRbcm93U3VtczIoYXNzYXkoc2VfcmVkKSkgPiAwXQpkaW0oc2VfcmVkKQoKbXUgPC0gcm93TWVhbnMyKGFzc2F5KHNlX3JlZCkpCnZhciA8LSByb3dWYXJzKGFzc2F5KHNlX3JlZCkpCmBgYAoKCmBgYHtyfQp0aWJibGUobXUsIHZhciwgZXJjY19nZW5lID0gc3RyX3N0YXJ0cyhyb3duYW1lcyhzZV9yZWQpLCAiRVJDQy0iKSkgJT4lCiAgbXV0YXRlKG11X3ByZWQgPSBtdSwgbXVfc3FfcHJlZCA9IG11XjIpICU+JQogIGdncGxvdChhZXMoeCA9IG11LCB5ID0gdmFyKSkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gImxpZ2h0Z3JheSIsIHNpemUgPSAwLjEpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCAlPiUgZmlsdGVyKHZhciA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICAjIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEgJiBtdSA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICBjb29yZF9maXhlZChleHBhbmQgPSBGQUxTRSwgY2xpcCA9ICJvZmYiKSArCiAgICBnZ3Jhc3RyOjpnZW9tX3BvaW50X3Jhc3QoYWVzKGNvbG9yID0gZXJjY19nZW5lKSwgc2l6ZSA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzY2FsZWQgPSBUUlVFLCBvdXRzaWRlID0gRkFMU0UsIHNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3J0ID0gdW5pdCgwLjA1LCAiY20iKSwgbWlkID0gdW5pdCgwLjEsICJjbSIpLCBsb25nID0gdW5pdCgwLjE1LCAiY20iKSkgKwogICAgc2NhbGVfeF9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNSksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihNZWFufihtdSkpKSArCiAgICBzY2FsZV95X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU2KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKFZhcmlhbmNlKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gIiM2YzU4ZDEiLCAiRkFMU0UiID0gImJsYWNrIikpICsKICAgIGdndGl0bGUoIlN2ZW5zc29uIDIwMTcgKDEpIiwgc3VidGl0bGUgPSAiIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKdGVjaF9wMiA8LSBsYXN0X3Bsb3QoKQpgYGAKCgpgYGB7cn0Kc2UgPC0gemVsbGtvbnZlcnRlcjo6cmVhZEg1QUQoIi4uL2RhdGEvc3ZlbnNzb25fMjAxN18yLmg1YWQiKQpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGVyY2NfZ2VuZSA9IHN0cl9zdGFydHMocm93bmFtZXMoc2VfcmVkKSwgIkVSQ0MtIikpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQgJT4lIGZpbHRlcih2YXIgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxICYgbXUgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgZ2dyYXN0cjo6Z2VvbV9wb2ludF9yYXN0KGFlcyhjb2xvciA9IGVyY2NfZ2VuZSksIHNpemUgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjNmM1OGQxIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJTdmVuc3NvbiAyMDE3ICgyKSIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnRlY2hfcDMgPC0gbGFzdF9wbG90KCkKYGBgCgoKCiMgQmlvbG9naWNhbCBjb250cm9sCgoKYGBge3J9CnNlIDwtIHplbGxrb252ZXJ0ZXI6OnJlYWRINUFEKCIuLi9kYXRhL25paDN0My5oNWFkIikKc2YgPC0gY29sU3VtczIoYXNzYXkoc2UpKQp0aHJlcyA8LSBxdWFudGlsZShzZiwgMC41KSAqIGMoMSwgMS4zKQpoaXN0KHNmLCBicmVha3MgPSA1MCk7IGFibGluZSh2ID0gdGhyZXMsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQoKc2VfcmVkIDwtIHNlWywgc2YgPiB0aHJlc1sxXSAmIHNmIDwgdGhyZXNbMl1dCnNmX3JlZCA8LSBzZltzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2VfcmVkIDwtIHNlX3JlZFtyb3dTdW1zMihhc3NheShzZV9yZWQpKSA+IDBdCmRpbShzZV9yZWQpCgptdSA8LSByb3dNZWFuczIoYXNzYXkoc2VfcmVkKSkKdmFyIDwtIHJvd1ZhcnMoYXNzYXkoc2VfcmVkKSkKYGBgCgoKYGBge3J9CnRpYmJsZShtdSwgdmFyLCBjZWxsX2N5Y2xlX2dlbmUgPSByb3duYW1lcyhzZV9yZWQpICVpbiUgcGFzdGUwKCJtbTEwXyIsIG1vdXNlX2NlbGxfY3ljbGVfZ2VuZXMpKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCAlPiUgZmlsdGVyKChmYWN0b3IgPT0gMTAwICYgdmFyIDwgMS41ZTMpIHwgKGZhY3RvciAhPSAxMDAgJiB2YXIgPCA0ZTMpKSwgCiAgICAgICAgICAgICAgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEgJiBtdSA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICAjIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgIyBnZW9tX3BvaW50KHNpemUgPSAwLjMsIGFscGhhID0gMC4zKSArCiAgICBnZ3Jhc3RyOjpnZW9tX3BvaW50X3Jhc3QoYWVzKGNvbG9yID0gY2VsbF9jeWNsZV9nZW5lKSwgc2l6ZSA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgYW5ub3RhdGUoc2hhZG93dGV4dDo6Okdlb21TaGFkb3dUZXh0LCB4ID0gNWUzLCB5ID0gNWUzLCBsYWJlbCA9IGV4cHJlc3Npb24oVmFyPT1tdSksCiAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC41LCBhbmdsZSA9IDQ1LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDRlMyksIHkgPSA0ZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KzEqbXVeMiksCiAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC40LCBhbmdsZSA9IGF0YW4oMikgLyBwaSAqIDE4MCwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIiwgYmcuY29sb3VyID0gIndoaXRlIikgKwogICAgYW5ub3RhdGUoc2hhZG93dGV4dDo6Okdlb21TaGFkb3dUZXh0LCB4ID0gc3FydCg1ZTMgLyAwLjAxKSwgeSA9IDVlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMC4wMSptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDJlMyAvIDEwMCksIHkgPSAyZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KzEwMCptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiTklILzNUMyBDZWxscyIsIHN1YnRpdGxlID0gIjxzcGFuIHN0eWxlID0gJ2NvbG9yOiAjODcxNzJmJz5DZWxsIGN5Y2xlIG1hcmtlcjwvc3Bhbj4gZ2VuZXMuIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKCnAxIDwtIGxhc3RfcGxvdCgpCmBgYAoKCgoKYGBge3J9CnNlIDwtIHplbGxrb252ZXJ0ZXI6OnJlYWRINUFEKCIuLi9kYXRhL2hlazI5M3QuaDVhZCIpCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQoKCmBgYAoKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBwYXN0ZTAoImhnMTlfIiwgaHVtYW5fY2VsbF9jeWNsZV9nZW5lcykpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQgJT4lIGZpbHRlcih2YXIgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxICYgbXUgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgZ2dyYXN0cjo6Z2VvbV9wb2ludF9yYXN0KGFlcyhjb2xvciA9IGNlbGxfY3ljbGVfZ2VuZSksIHNpemUgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjODcxNzJmIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJIRUsgMjkzVCBDZWxscyIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnAyIDwtIGxhc3RfcGxvdCgpCmBgYAoKCgpgYGB7cn0Kc2VfZnVsbCA8LSByZWFkUkRTKCIuLi9kYXRhL25jaS1oMTk3NS5SZHMiKQp0YWJsZShzZV9mdWxsJGNlbGxfbGluZSkKYGBgCgpgYGB7cn0Kc2UgPC0gc2VfZnVsbFssIHNlX2Z1bGwkY2VsbF9saW5lID09ICJIMTk3NSJdCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBodW1hbl9jZWxsX2N5Y2xlX2dlbmVzKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIodmFyIDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBjZWxsX2N5Y2xlX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiTkNJLUgxOTc1IENlbGxzIiwgc3VidGl0bGUgPSAiIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKcDMgPC0gbGFzdF9wbG90KCkKYGBgCgoKCmBgYHtyfQpzZSA8LSByZWFkUkRTKCIuLi9kYXRhL0dTRTEyNjMyMS5SZHMiKQojIHRhYmxlKHNlJGNlbGxQaGFzZSkKIyBzZSA8LSBzZVssIHNlJGNlbGxQaGFzZSA9PSAiUyJdCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBodW1hbl9jZWxsX2N5Y2xlX2dlbmVzKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIodmFyIDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBjZWxsX2N5Y2xlX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiR00xODUwMiBDZWxscyIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnA0IDwtIGxhc3RfcGxvdCgpCmBgYAoKCgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2ggPSA4fQpwX3RlY2ggPC0gY293cGxvdDo6cGxvdF9ncmlkKHRlY2hfcDEsIHRlY2hfcDIsIHRlY2hfcDMsIE5VTEwsIG5yb3cgPSAxLCBhbGlnbiA9ICJoIikKcF9iaW8gPC0gY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBucm93ID0gMSwgYWxpZ24gPSAiaCIpCgp0ZWNoX3RpdGxlIDwtIGNvd3Bsb3Q6OmdnZHJhdygpICsgY293cGxvdDo6ZHJhd19sYWJlbCgiKEEpIERyb3BsZXRzIHdpdGggUk5BIHNvbHV0aW9uICh0ZWNobmljYWwgY29udHJvbCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIHggPSAwLjAyLCBoanVzdCA9IDAsIHNpemUgPSAxOCkKYmlvX3RpdGxlIDwtIGNvd3Bsb3Q6OmdnZHJhdygpICsgY293cGxvdDo6ZHJhd19sYWJlbCgiKEIpIENlbGwgbGluZSBwb3B1bGF0aW9ucyAoYmlvbG9naWNhbCBjb250cm9sKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLCB4ID0gMC4wMiwgaGp1c3QgPSAwLCBzaXplID0gMTgpCgpwX3JlcyA8LSBjb3dwbG90OjpwbG90X2dyaWQodGVjaF90aXRsZSwgcF90ZWNoLCBiaW9fdGl0bGUsIHBfYmlvLCBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjIsIDEsIDAuMiwgMSkpCnBfcmVzCmBgYAoKCmBgYHtyfQpjb3dwbG90OjpzYXZlX3Bsb3QoIi4uL291dHB1dC9tZWFuX3ZhcmlhbmNlX3JlbGF0aW9uX2hvbW5vZ2VuZW91c19jZWxscy5wZGYiLCBwX3JlcywgbnJvdyA9IDIsIG5jb2wgPSA0LCBiYXNlX2FzcCA9IDAuNjgsIGJhc2VfaGVpZ2h0ID0gNSkKYGBgCgoKCgoKCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo=